﻿' One row in the diagram. Contains a collection of DiagramGroup objects 
' that are arranged within the row.
' 
' Supports the VerticalAlignment property so groups can be top or bottom 
' aligned. Supports the Margin property which is used to control space
' between the rows on the diagram.
Imports System
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.Windows.Controls
Imports System.Windows
Imports System.Windows.Media



''' <summary>
''' Row in the diagram that contains group objects.
''' </summary>
Public Class DiagramRow
    Inherits FrameworkElement

#Region " fields "

    ' Space between each group.
    Private m_groupSpace As Double = 80

    ' Location of the row, relative to the diagram.
    Private m_location As New Point()

    ' List of groups in the row.
    Private m_groups As New List(Of DiagramGroup)

#End Region

#Region " properties "

    ''' <summary>
    ''' Space between each group.
    ''' </summary>
    Public Property GroupSpace() As Double
        Get
            Return m_groupSpace
        End Get
        Set(ByVal value As Double)
            m_groupSpace = value
        End Set
    End Property

    ''' <summary>
    ''' Location of the row, relative to the diagram.
    ''' </summary>
    Public Property Location() As Point
        Get
            Return m_location
        End Get
        Set(ByVal value As Point)
            m_location = value
        End Set
    End Property

    ''' <summary>
    ''' List of groups in the row.
    ''' </summary>
    Public ReadOnly Property Groups() As ReadOnlyCollection(Of DiagramGroup)
        Get
            Return New ReadOnlyCollection(Of DiagramGroup)(m_groups)
        End Get
    End Property

    Public ReadOnly Property NodeCount() As Integer
        Get
            Dim count As Integer = 0
            For Each group In Groups
                count += group.Nodes.Count
            Next
            Return count
        End Get
    End Property

#End Region

#Region " overrides "

    Protected Overrides Function MeasureOverride(ByVal availableSize As Size) As Size
        ' Let each group determine how large they want to be.
        Dim size As New Size(Double.PositiveInfinity, Double.PositiveInfinity)
        For Each group In Groups
            group.Measure(size)
        Next
        ' Return the total size of the row.
        Return ArrangeGroups(False)
    End Function

    Protected Overrides Function ArrangeOverride(ByVal finalSize As Size) As Size
        ' Arrange the groups in the row, return the total size.
        Return ArrangeGroups(True)
    End Function


    Protected Overrides ReadOnly Property VisualChildrenCount() As Integer
        Get
            ' Return the number of groups.
            Return Groups.Count
        End Get
    End Property

    Protected Overrides Function GetVisualChild(ByVal index As Integer) As Visual
        ' Return the requested group.
        Return Groups(index)
    End Function

#End Region

    ''' <summary>
    ''' Add the group to the row.
    ''' </summary>
    Public Sub Add(ByVal group As DiagramGroup)
        m_groups.Add(group)
        Me.AddVisualChild(group)
    End Sub

    ''' <summary>
    ''' Remove all groups from the row.
    ''' </summary>
    Public Sub Clear()
        For Each group In m_groups
            group.Clear()
            Me.RemoveVisualChild(group)
        Next
        m_groups.Clear()
    End Sub


    ''' <summary>
    ''' Arrange the groups in the row, return the total size.
    ''' </summary>
    Private Function ArrangeGroups(ByVal arrange As Boolean) As Size
        ' Position of the next group.
        Dim pos As Double = 0

        ' Bounding area of the group.
        Dim bounds As Rect = New Rect()

        ' Total size of the row.
        Dim totalSize As New Size(0, 0)

        For Each group In m_groups
            ' Group location.
            bounds.X = pos
            bounds.Y = 0

            ' Group size.                    
            bounds.Width = group.DesiredSize.Width
            bounds.Height = group.DesiredSize.Height

            ' Arrange the group, save the location.
            If arrange Then
                group.Arrange(bounds)
                group.Location = bounds.TopLeft
            End If

            ' Update the size of the row.
            totalSize.Width = pos + group.DesiredSize.Width
            totalSize.Height = Math.Max(totalSize.Height, group.DesiredSize.Height)

            pos += (bounds.Width + Me.GroupSpace)
        Next
        Return totalSize
    End Function


End Class
